﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Walson.Windows.Forms
{
    /// <summary>
    /// LED 点阵屏
    /// </summary>
    public partial class LedMatrixScreen : Control
    {
        /// <summary>
        /// 枚举：点阵屏的模式
        /// </summary>
        public enum Modes
        {
            /// <summary>
            /// 文本模式
            /// </summary>
            Text,
            /// <summary>
            /// 图形模式
            /// </summary>
            Graphic
        }


        #region 局部变量

        private bool[,] _Buf1, _Buf2;
        private Bitmap _GraphicBuf;
        private int _Row, _Col;

        private Pen _DarkPen, _LightPen;
        private SolidBrush _DarkBrush=new SolidBrush(Color.DarkRed), _LightBrush=new SolidBrush(Color.Red);

        private Graphics _FontMeasureG = Graphics.FromImage(new Bitmap(1, 1));
        #endregion



        #region 属性
        private Modes _Mode = Modes.Graphic;
        /// <summary>
        /// 选择的模式
        /// </summary>
        public Modes Mode
        {
            get
            {
                return _Mode;
            }
            set
            {
                if (_Mode != value)
                {
                    _Mode = value;
                }
            }
        }

        private int _DotSize = 5;
        /// <summary>
        /// 点的大小
        /// </summary>
        public int DotSize
        {
            get
            {
                return _DotSize;
            }
            set
            {
                if (_DotSize != value)
                {
                    _DotSize = value;
                }
            }
        }

        private int _DotGap = 3;
        /// <summary>
        /// 点间距
        /// </summary>
        public int DotGap
        {
            get
            {
                return _DotGap; 
            }
            set
            {
                if(_DotGap!=value)
                {
                    _DotGap = value;
                }
            }
        }


        private Color _LightDotColor = Color.Red;
        /// <summary>
        /// 点亮的点的颜色
        /// </summary>
        public Color LightDotColor
        {
            get
            {
                return _LightDotColor;
            }
            set
            {
                if(_LightDotColor!=value)
                {
                    _LightDotColor = value;
                    _LightPen = new Pen(value);
                    _LightBrush = new SolidBrush(value);
                    this.Display();
                }
            }
        }

        private Color _DarkDotColor = Color.DarkRed;
        /// <summary>
        /// 未点亮的点的颜色
        /// </summary>
        public Color DarkDotColor
        {
            get
            {
                return _DarkDotColor;
            }
            set
            {
                if(_DarkDotColor!=value)
                {
                    _DarkDotColor = value;
                    _DarkPen = new Pen(value);
                    _DarkBrush = new SolidBrush(value);
                    this.Display();
                }
            }
        }
        #endregion 属性

        #region 方法

        /// <summary>
        /// 位图转换
        /// </summary>
        /// <param name="bmp">黑底白字的位图</param>
        /// <returns>点阵数组</returns>
        private bool[,]BmpComverter(Bitmap bmp)
        {
            bool[,] result = new bool[bmp.Width, bmp.Height];

            for(int x=0;x<bmp.Width;x++)
            {
                for(int y=0;y<bmp.Height;y++)
                {
                    Color c=bmp.GetPixel(x,y);
                    result[x, y] = (c.A > 0 && c.R == 255 && c.G == 255 && c.B == 255);
                }
            }

            return result;
        }













        /// <summary>
        /// 显示图像
        /// </summary>
        public void Display()
        {
            if (_Buf1 == null)
                return;

            int X = _Buf1.GetUpperBound(0), Y = _Buf1.GetUpperBound(1);
            using (Graphics g = Graphics.FromImage(_GraphicBuf))
            {
                int x, y;
                int grid = _DotSize + _DotGap;
                int offsetX = (this.Width - (_Col * grid - _DotGap)) / 2;
                int offsetY = (this.Height - (_Row * grid - _DotGap)) / 2;
                int indexX, indexY;

                X = X * grid + offsetX;
                Y = Y * grid + offsetY;

                indexY = 0;
                for (y = offsetY; y <= Y; y += grid)
                {
                    indexX = 0;
                    for (x = offsetX; x <= X; x += grid)
                    {
                        if (_Buf1[indexX, indexY] != _Buf2[indexX, indexY])
                            g.FillEllipse(_LightBrush, x, y, _DotSize, _DotSize);
                        else
                            g.FillEllipse(_DarkBrush, x, y, _DotSize, _DotSize);
                        indexX++;
                    }
                    indexY++;
                }
            }

            this.Invalidate();
        }

        /// <summary>
        /// 画字符串
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="str"></param>
        /// <param name="font"></param>
        public void DrawString(int x, int y, string str,Font font)
        {
            SizeF size = _FontMeasureG.MeasureString(str, font);
            int width=(int)size.Width + 1;
            int height=(int)size.Height + 1;
            bool[,] strArray;
            int X = _Buf1.GetUpperBound(0);
            int Y = _Buf1.GetUpperBound(1);
            using(Bitmap bmp=new Bitmap(width,height))
            {
                using(Graphics g=Graphics.FromImage(bmp))
                {
                    g.Clear(Color.Black);
                    g.DrawString(str, font, Brushes.White, 0, 0);
                    strArray=BmpComverter(bmp);
                }
            }

            for(int xx=x;xx<x+width;xx++)
            {
                for(int yy=y;yy<y+height;yy++)
                {
                    _Buf2[xx + x, yy + y] = strArray[xx, yy];
                }
            }
        }

        public void Test()
        {
            int X = _Buf1.GetUpperBound(0);
            for (int x = 0; x <= X; x++)
            {
                _Buf2[x, 0] = ((x % 2) == 0);
            }

            for (int x = 0; x <= X; x++)
            {
                _Buf2[x, 1] = ((x % 3) == 0);
            }

            Display();
        }

        #endregion

        /// <summary>
        /// 点阵屏
        /// </summary>
        public LedMatrixScreen()
        {
            InitializeComponent();

            this.DoubleBuffered = true;

            this.SizeChanged += LedMatrixScreen_SizeChanged;
        }

        private void LedMatrixScreen_SizeChanged(object sender, EventArgs e)
        {
            int newCol, newRow;
            newCol = this.Width / (_DotSize + _DotGap);
            newRow = this.Height / (_DotSize + _DotGap);
            bool[,] newBuf = new bool[newCol, newRow];

            int xx = Math.Min(_Col, newCol), yy = Math.Min(_Row, newRow);

            for(int x=0;x<xx;x++)
                for(int y=0;y<yy;y++)
                {
                    newBuf[x, y] = _Buf1[x, y];
                }

            _Col = newCol;
            _Row = newRow;

            _Buf1 = null;
            _Buf1 = newBuf;
            _Buf2 = new bool[newCol, newRow];
            if (_GraphicBuf != null)
            {
                _GraphicBuf.Dispose();
                _GraphicBuf = null;
            }

            _GraphicBuf = new Bitmap(this.Width, this.Height);
            using(Graphics g=Graphics.FromImage(_GraphicBuf))
            {
                int x, y;
                int X = _Buf1.GetUpperBound(0), Y = _Buf1.GetUpperBound(1);
                int grid = _DotSize + _DotGap;
                int offsetX = (this.Width - (newCol * grid - _DotGap)) / 2;
                int offsetY = (this.Height - (newRow * grid - _DotGap)) / 2;

                X = X * grid + offsetX;
                Y = Y * grid + offsetY;

                for (y = offsetY; y <= Y; y += grid)
                {
                    for (x = offsetX; x <= X; x += grid)
                    {
                        g.FillEllipse(_DarkBrush, x, y, _DotSize, _DotSize);
                    }
                }
            }
        }

        /// <summary>
        /// 重绘
        /// </summary>
        /// <param name="pe">参数</param>
        protected override void OnPaint(PaintEventArgs pe)
        {
            if (_Buf1 == null)
                return;

            if (_GraphicBuf == null)
                return;

            if (_Col == 0 || _Row == 0)
                return;

            pe.Graphics.DrawImage(_GraphicBuf, 0, 0);
        }
    }
}
